﻿/*
 * @Autor: PK
 * @Date: 2022/01/06 14:55:SS
 */

using System;
using System.Collections.Generic;
using System.Diagnostics;
using ShkSimulation.core.template.customer;
using ShkSimulation.carsharing.impl.elements;

namespace ShkSimulation.carsharing.impl.model.dispatch {

	public class DefaultDispatchHelper: DispatchHelper {

		private QueueNetwork network;

		public DefaultDispatchHelper(QueueNetwork network) {
			this.network = network;
		}

		public void TryDispatch(Station currentStation) {
			Dictionary<int, DispatchInfo> dispatchInfos = CalculateAllDispatchInfo();
			List<Dispatcher> dispatchers = ExecuteDispatch(dispatchInfos);
			List<Dispatcher> allocatedDispatchers = AllocateDispatcher(dispatchInfos);
			foreach (var dispatcher in dispatchers) {
				dispatcher.StartDispatch(currentStation.ClockTime);
			}
			foreach (var allocatedDispatcher in allocatedDispatchers) {
				allocatedDispatcher.EnterNextAgency();
			}
		}

		#region 执行调度

		private List<Dispatcher> ExecuteDispatch(Dictionary<int, DispatchInfo> dispatchInfos) {
			// 要车的站台
			Dictionary<int, DispatchInfo> stationNeedVehicle = new Dictionary<int, DispatchInfo>();
			// 车多的站台
			Dictionary<int, DispatchInfo> stationVehicleExceed = new Dictionary<int, DispatchInfo>();			
			foreach (var (key, station) in network.Stations) {
				DispatchInfo dispatchInfo = dispatchInfos[key];
				if (dispatchInfo.LackVehicleCount > 0) {
					stationNeedVehicle.Add(key, dispatchInfo);
				}else if (dispatchInfo.VehicleCountExceed > 0) {
					stationVehicleExceed.Add(key, dispatchInfo);
				}
			}
			if (stationNeedVehicle.Count == 0 || stationVehicleExceed.Count == 0) {
				return new List<Dispatcher>();
			}
			return ExecuteDispatch(stationNeedVehicle, stationVehicleExceed);
		}

		private List<Dispatcher> ExecuteDispatch(Dictionary<int,DispatchInfo> stationNeedVehicle, 
			Dictionary<int,DispatchInfo> stationVehicleExceed) {

			List<Dispatcher> dispatchers = new List<Dispatcher>();
			// 第一步将所有可以调度的执行了
			foreach (var (needkey, needInfo) in stationNeedVehicle) {
				if (needInfo.LackVehicleCount == 0) {
					continue;
				}
				Debug.Assert(needInfo.LackVehicleCount > 0, $"{needInfo.LackVehicleCount} not bigger than 0");
				foreach (var (exceedKey, exceedInfo) in stationVehicleExceed) {
					if (exceedInfo.VehicleCountExceed == 0 || exceedInfo.UsableDispatcherCount == 0) {
						continue;
					}
					if (needInfo.LackVehicleCount == 0) {
						break;
					}
					Debug.Assert(exceedInfo.UsableDispatcherCount > 0, $"{exceedInfo.UsableDispatcherCount} not bigger than 0");
					Debug.Assert(exceedInfo.VehicleCountExceed > 0, $"{exceedInfo.VehicleCountExceed} not bigger than 0");
					Debug.Assert(needInfo.LackVehicleCount > 0, $"{needInfo.LackVehicleCount} not bigger than 0");
					int dispatcherCount = exceedInfo.UsableDispatcherCount;
					int realCount = Math.Min(needInfo.LackVehicleCount, exceedInfo.VehicleCountExceed);
					realCount = Math.Min(dispatcherCount, realCount);
					if (realCount > 0) {
						needInfo.LackVehicleCount -= realCount;
						exceedInfo.VehicleCountExceed -= realCount;
						exceedInfo.UsableDispatcherCount -= realCount;
						dispatchers.AddRange(PrepareDispatch(network.Stations[exceedKey], network.Stations[needkey], realCount));
					}
				}
			}
			return dispatchers;

		}

		private List<Dispatcher> PrepareDispatch(Station exceed, Station need, int dispatchCount) {
			List<Dispatcher> dispatchers = new List<Dispatcher>(dispatchCount);
			for (int i = 0; i < dispatchCount; i++) {
				Dispatcher dispatcher = exceed.GetDispatcher();
				Debug.Assert(dispatcher.Vehicle == null, "带车出走, 问题大大");
				Vehicle vehicle = exceed.GetDispatcherFreeVehicle();
				vehicle.BindCustomer(dispatcher);
				CustomerTemplate customerTemplate = network.DemandManager.GetCustomerTemplateByAgenciesIds(exceed.UniqueId, need.UniqueId);
				dispatcher.SetRoute(customerTemplate.GetCustomerAgencies());
				dispatcher.SkipAgency(1);
				dispatchers.Add(dispatcher);
			}
			return dispatchers;
		}

		#endregion

		#region 分配调度员
		
		private List<Dispatcher> AllocateDispatcher(Dictionary<int, DispatchInfo> dispatchInfos) {
			// 缺调度员的站台
			Dictionary<int, DispatchInfo> stationNeedDispatcher = new Dictionary<int, DispatchInfo>();
			// 有多余调度员的站台
			Dictionary<int, DispatchInfo> stationDispatcherExceed = new Dictionary<int, DispatchInfo>();
			foreach (var (key, dispatchInfo) in dispatchInfos) {
				Debug.Assert(dispatchInfo.UsableDispatcherCount >= 0, $"{dispatchInfo.UsableDispatcherCount} >= 0");
				if (dispatchInfo.UsableDispatcherCount == 0 && dispatchInfo.VehicleCountExceed > 0) {
					// 缺调度员的是车多没运完的
					dispatchInfo.LackDispatcherCount = dispatchInfo.VehicleCountExceed;
					stationNeedDispatcher.Add(key, dispatchInfo);
				}else if (dispatchInfo.UsableDispatcherCount > 0) {
					stationDispatcherExceed.Add(key, dispatchInfo);
				}
			}
			if (stationNeedDispatcher.Count == 0 || stationDispatcherExceed.Count == 0) {
				return new List<Dispatcher>();
			}
			return AllocateDispatcher(stationNeedDispatcher, stationDispatcherExceed);
		}

		private List<Dispatcher> AllocateDispatcher(Dictionary<int, DispatchInfo> stationNeedDispatcher, Dictionary<int, DispatchInfo> stationDispatcherExceed) {
			List<Dispatcher> dispatchers = new List<Dispatcher>();
			foreach (var (needkey, needInfo) in stationNeedDispatcher) {
				if (needInfo.LackDispatcherCount == 0) {
					continue;
				}
				foreach (var (exceedKey, exceedInfo) in stationDispatcherExceed) {
					if (exceedInfo.UsableDispatcherCount == 0) {
						continue;
					}
					if (needInfo.LackDispatcherCount == 0) {
						break;
					}
					int realCount = Math.Min(needInfo.LackDispatcherCount, exceedInfo.UsableDispatcherCount);
					if (realCount > 0) {
						needInfo.LackDispatcherCount -= realCount;
						exceedInfo.UsableDispatcherCount -= realCount;
						dispatchers.AddRange(PrepareAllocate(network.Stations[exceedKey], network.Stations[needkey], realCount));
					}
				}
			}
			return dispatchers;
		}
		
		private List<Dispatcher> PrepareAllocate(Station exceed, Station need, int dispatchCount) {
			List<Dispatcher> dispatchers = new List<Dispatcher>(dispatchCount);
			for (int i = 0; i < dispatchCount; i++) {
				Dispatcher dispatcher = exceed.GetDispatcher();
				Debug.Assert(dispatcher.Vehicle == null, "带车出走, 问题大大");
				CustomerTemplate customerTemplate = network.DemandManager.GetCustomerTemplateByAgenciesIds(exceed.UniqueId, need.UniqueId);
				dispatcher.SetRoute(customerTemplate.GetCustomerAgencies());
				dispatcher.SkipAgency(1);
				dispatchers.Add(dispatcher);
			}
			return dispatchers;
		}
		#endregion

		public int LowerBound { get; set; } = 3;
		public int UpperBound { get; set; } = 7;
		
		private Dictionary<int, DispatchInfo> CalculateAllDispatchInfo() {
			Dictionary<int, DispatchInfo> dictionary = new Dictionary<int, DispatchInfo>();
			foreach (var (key, station) in network.Stations) {
				DispatchInfo info = CalculateDispatchInfo(station.GetDispatcherInfo());
				dictionary.Add(key, info);
			}
			return dictionary;
		}
		
		private DispatchInfo CalculateDispatchInfo(DispatchInfo currentStation) {
			// 调度员都可用
			currentStation.UsableDispatcherCount = currentStation.FreeDispatcherCount;
			if (LowerBound > currentStation.FreeVehicleCount) {
				// 低于阈值，可用车为负
				currentStation.LackVehicleCount = LowerBound - currentStation.FreeVehicleCount;
			}else if (currentStation.FreeVehicleCount > UpperBound) {
				// 高于阈值，可用车为正
				currentStation.VehicleCountExceed = currentStation.FreeVehicleCount - UpperBound;
			}
			return currentStation;
		}

	}

}